package scatter.common.rest.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import scatter.common.pojo.po.BasePo;
import scatter.common.rest.dataconstraint.DataConstraintService;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基础能用服务类，提供最常用的服务逻辑
 * Created by yangwei
 * Created at 2020/10/27 15:49
 */
@Transactional
public class IBaseServiceImpl<Mapper extends IBaseMapper<Po>,Po extends BasePo> extends ServiceImpl<Mapper,Po> implements IBaseService<Po>  {

    @Autowired
    protected DataConstraintService dataConstraintService;

    @Autowired(required = false)
    private List<IDeleteServiceListener<Po>> deleteServiceListeners;

    /**
     * 获取查询数据范围约束服务
     * @return
     */
    DataConstraintService getQueryDataConstraintService(){
        return dataConstraintService;
    }

    /**
     * 获取删除数据范围约束服务
     * @return
     */
    DataConstraintService getDeleteDataConstraintService(){
        return dataConstraintService;
    }

    @Override
    public Po queryById(String id) {
        Assert.hasText(id,"id 不能为空");
        QueryWrapper<Po> queryWrapper = Wrappers.<Po>query().eq(BasePo.COLUMN_ID, id);

        getQueryDataConstraintService().dataConstraint(queryWrapper);
        Po dbPo = getOne(queryWrapper,true);
        return dbPo;
    }

    /**
     * 根据id删除前
     * @param id
     */
    protected void preDeleteById(String id,Po po){}

    /**
     * 删除前调用
     * @param id
     * @param po
     * @param options
     */
    private void preDeleteById(String id,Po po,Object options){
        preDeleteById(id,po);
        if (!isEmpty(deleteServiceListeners)) {
            deleteServiceListeners.parallelStream().forEach(listener->listener.preDeleteById(id,po));
        }
    }

    /**
     * 根据id删除后
     * @param id
     */
    protected void postDeleteById(String id,Po po){}

    /**
     * 删除后调用
     * @param id
     * @param po
     * @param options
     */
    private void postDeleteById(String id,Po po,Object options){
        postDeleteById(id,po);
        if (!isEmpty(deleteServiceListeners)) {
            deleteServiceListeners.parallelStream().forEach(listener->listener.postDeleteById(id,po));
        }
    }

    @Override
    public boolean deleteById(String id) {
        Assert.hasText(id,"id 不能为空");
        Po byId = getById(id);
        preDeleteById(id,byId,null);
        QueryWrapper<Po> queryWrapper = Wrappers.<Po>query().eq(BasePo.COLUMN_ID, id);

        getDeleteDataConstraintService().dataConstraint(queryWrapper);
        boolean r = remove(queryWrapper);
        if(r){
            postDeleteById(id,byId,null);
        }
        return r;
    }
    /**
     * 根据id删除前
     * @param columnId
     */
    protected void preDeleteByColumn(String columnId , SFunction<Po, ?> column,List<Po> pos){}

    /**
     * 根据列删除前调用
     * @param columnId
     * @param column
     * @param pos
     * @param options
     */
    private void preDeleteByColumn(String columnId, SFunction<Po, ?> column ,List<Po> pos ,Object options){
        preDeleteByColumn(columnId,column,pos);
        if (!isEmpty(deleteServiceListeners)) {
            deleteServiceListeners.parallelStream().forEach(listener->listener.preDeleteByColumn(columnId,column,pos));
        }
    }

    /**
     * 根据id删除后
     * @param columnId
     */
    protected void postDeleteByColumn(String columnId , SFunction<Po, ?> column ,List<Po> pos){}

    /**
     * 根据列删除后调用
     * @param columnId
     * @param column
     * @param pos
     * @param options
     */
    private void postDeleteByColumn(String columnId , SFunction<Po, ?> column ,List<Po> pos ,Object options){
        postDeleteByColumn(columnId ,column ,pos);
        if (!isEmpty(deleteServiceListeners)) {
            deleteServiceListeners.parallelStream().forEach(listener->listener.postDeleteByColumn(columnId,column,pos));
        }
    }
    @Override
    public boolean deleteByColumn(String columnId, SFunction<Po, ?> column) {
        Assert.notNull(column,"column不能为空");
        Assert.hasText(columnId,"columnId不能为空");
        LambdaQueryWrapper<Po> queryWrapper = Wrappers.<Po>lambdaQuery().eq(column, columnId);
        getDeleteDataConstraintService().dataConstraint(queryWrapper);
        List<Po> list = list(queryWrapper);
        preDeleteByColumn(columnId,column,list,null);

        boolean r = remove(queryWrapper);
        if(r){
            postDeleteByColumn(columnId,column,list,null);
        }
        return r;
    }

    @Override
    public boolean saveOrUpdateBatchByUniqueColumn(Collection<Po> entityList, SFunction<Po, ?> column, int batchSize) {
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
        com.baomidou.mybatisplus.core.toolkit.Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
        String keyProperty = tableInfo.getKeyProperty();
        String columnProperty = SFunctionHelperTool.columnPropertyString(column);
        String columnReal = SFunctionHelperTool.columnToString(column);
        com.baomidou.mybatisplus.core.toolkit.Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
        return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> {

            Object columnVal = ReflectionKit.getFieldValue(entity, columnProperty);

           /* 因为不是主键，这里不用了，直接调用数据库查询，因为使用这个导致数据添加不上
            boolean b = StringUtils.checkValNull(columnVal);
            if (!b) {
                return b;
            }*/
            Map<String, Object> columnMap = new HashMap<>();
            columnMap.put(columnReal,columnVal);
            return CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_MAP), columnMap));
        }, (sqlSession, entity) -> {
            Map<String, Object> map = CollectionUtils.newHashMapWithExpectedSize(2);
            map.put(Constants.ENTITY, entity);
            Object columnVal = ReflectionKit.getFieldValue(entity, columnProperty);

            UpdateWrapper<Object> updateWrapper = Wrappers.update().eq(columnReal, columnVal);
            map.put(Constants.WRAPPER, updateWrapper);
            sqlSession.update(getSqlStatement(SqlMethod.UPDATE), map);
        });
    }

    @Override
    public boolean updateBatchByUniqueColumn(Collection<Po> entityList, SFunction<Po, ?> column, int batchSize) {

        String columnProperty = SFunctionHelperTool.columnPropertyString(column);
        String columnReal = SFunctionHelperTool.columnToString(column);
        return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
            Map<String, Object> map = CollectionUtils.newHashMapWithExpectedSize(2);
            map.put(Constants.ENTITY, entity);
            Object columnVal = ReflectionKit.getFieldValue(entity, columnProperty);

            UpdateWrapper<Object> updateWrapper = Wrappers.update().eq(columnReal, columnVal);
            map.put(Constants.WRAPPER, updateWrapper);
            sqlSession.update(getSqlStatement(SqlMethod.UPDATE), map);
        });
    }

}
